# -*-coding:Utf-8 -*
""" Player module
"""
import bge,mathutils,math,aud,random
from time import time
if __name__ == "__main__" or not "core" in bge.__dict__:
	raise ImportError("this module is not standalone, please import sealed zone module.")
Core = bge.core
Inputs = Core.inputs
Gameplay = Core.gameplay
SZ_Globals = Core.SZ_Globals
device = SZ_Globals['AU_Device']

class SZFirstPersonCam(Core.Twin,Gameplay.MouseView,bge.types.KX_GameObject):
	
	def __init__(self, old_owner, motherOb=None):
		Core.BasicEvent.__init__(self)
		Core.Twin.__init__(self, motherOb,{'mouse':Inputs.MouseTracking()},
					{'viewX':Gameplay.MouseView.Dimension(),
					'viewY':Gameplay.MouseView.Dimension()})
		self.layer = 'lvl'
		self.y.limit = [1.5,-1.3]
		self.x_object = self.parent.parent
		self.y_object = self.parent
		
		self.testerror = False
		
	@property
	def mouse(self):
		return self.settings['mouse']
	
	@property
	def x(self):
		return self.stats['viewX']
		
	@property
	def y(self):
		return self.stats['viewY']
	
	def activate(self):
		self.mouse.override = True
		Core.BasicEvent.activate(self)
		
	def update(self):
		if self.testerror:
			self.stop()
		self.testerror = True
		if self.mouse.axex:
			self.x.applyRot(self.mouse.axex)
			s = math.sin(self.x.rRot)
			c = math.cos(self.x.rRot)
			#self.x_object.applyRotation((.0,.0,self.mouse.axex*-1.0),True)
			self.x_object.localOrientation = ((c,-s,.0),(s,c,.0),(.0,.0,1.0))
		if self.mouse.axey:
			preRot = self.y.dRot
			self['rotation'] = str(self.y.applyRot(self.mouse.axey))
			self.y_object.playAction("view",preRot+90,self.y.dRot+90,2,50)
		else:
			self.y_object.playAction("view",self.y.dRot+90,self.y.dRot+90,2,50,play_mode=bge.logic.KX_ACTION_MODE_LOOP)
		#self.y_object.playAction('ironsight_pose',10,12,1,50)
		self.testerror = False
		
class SZHeldWeapon(Gameplay.HeldWeapon):
	
	useMethod = ('reloading',)
	
	def __init__(self,
				player_object,
				we_object,
				clip_object,
				inpMap = None,
				basic_item = None,
				firstUse = bge.events.LEFTMOUSE,
				secondUse = bge.events.RIGHTMOUSE, 
				thirdUse = bge.events.MIDDLEMOUSE,
				reloadWeapon = bge.events.RKEY):
		self.playerOb = player_object
		self.weaponGameOb = we_object
		self.clipGameOb = clip_object
		if inpMap == None and issubclass(type(player_object),Core.Twin):
			inpMap = player_object
		Gameplay.HeldWeapon.__init__(self,inpMap,basic_item,firstUse,secondUse,thirdUse)
		inpMap = self.settings['inputsMap']
		if type(self.settings['default_weapon']) == Gameplay.HeldWeapon.defaultNulWeapon:
			self.settings['default_weapon'].taken = SZHeldWeapon.takeNothing
			self.settings['default_weapon'].taken(self)
		self.settings['weapon_input'].append(Inputs.Input(
			inpMap,
			reloadWeapon
		).addAct(self.GetActionFrom('reloading')))
		self.stats['reloading'] = False
		
	def takeNothing(self):
		self.weaponGameOb.replaceMesh('weapon_point_debug')
		self.clipGameOb.replaceMesh('clip_point_debug')
		self.weaponGameOb.visible = False
		self.clipGameOb.visible = False
		
	def reloading(self,active):
		self.stats['primary_weapon'].reloading(self,active)
		
		
		
class SZPlayer(Core.BasicEvent,Core.Twin,bge.types.KX_GameObject):
	
	def __init__(self, old_owner,motherOb = None):
		"""self.settings = {
			"smoothMoveTime":0.2,
			"smoothMoveFactor":0.3,
			"angleMin" : 35.0,
			"angleMax" : 55.0,
			"gravity" : 9.81,
			"jumpforce" : 0.45,
			"jumpspeedup" : 1.436
		}"""
		Core.BasicEvent.__init__(self)
		self.layer = 'lvl'
		if motherOb != None:
			inpMap = motherOb.settings['inputsMap']
		else:
			inpMap = Inputs.InputMap()
			inpMap.layer = self.layer
		Core.Twin.__init__(self, motherOb,{'inputsMap':inpMap,
								'feet':self.scene.objects["Player_feet"],
								'smoothMoveFactor':0.3,
								'jumpforce' : 32.0,
								'gravity':9.81},
				{'velocity':mathutils.Vector((.0,.0)),
				 'move':mathutils.Vector((.0,.0)),
				 'falling':{'fall_time':.0,
							'pre_fall_speed':mathutils.Vector((.0,.0,.0))},
				 'jump':False,
				 'crouch':False
				 })
		self.characterW = bge.constraints.getCharacter(self)
		self.settings['speed'] = [15,13,0]
		
		# Set some settings as attribute (for convenience only)
		self.feet = self.settings['feet']
		
		# Get sensor object
		self.fallsens = self.scene.objects["falldetector"]
		
		Inputs.Input(inpMap,bge.events.SPACEKEY).addAct(self.jump)
		Inputs.Input(inpMap,bge.events.LEFTCTRLKEY).addAct(self.crouch)
		
		"""
		self.move_speed = [15,13]
		self._move_velocity_x = AnimateValue(0,self.settings["smoothMoveTime"])
		self._move_velocity_x.layer = self.layer
		self._move_velocity_y = AnimateValue(0,self.settings["smoothMoveTime"])
		self._move_velocity_y.layer = self.layer
		
		self.armature = self.children['armature']
		
		self.characterW.gravity = 0.0
		self.falltime = 0.0
		self._real_vector = mathutils.Vector((.0,.0,.0))
		self.collision = None
		self.fallCollision = None
		self.onGround = False
		self._jump = False
		self._crouch = False
		self._sprint = False
		self.prefallspeed = 0.0
		self.collisionCallbacks.append(self.onCollision)
		#self.fallsens.setParent(self,False,True)
		self.fallsens.collisionCallbacks.append(self.onFallCollision)
		self.scene.pre_draw.append(self.resetCollisionState)
		self.armature.playAction('general_pose', .0, 10.0, 0,60)
		self.footstep = SZ_Globals['level']['footstep_sound']
		self.footsound_evt = Event(self.footstepUpdate)
		self.footsound_evt.layer = 'lvl'
		self.footsound_evt.recurrentEvent(0.33333)"""
		self.testerror = False
		
	def activate(self):
		self.settings['inputsMap'].activate()
		Core.BasicEvent.activate(self)
	def stop(self):
		self.settings['inputsMap'].stop()
		Core.BasicEvent.stop(self)
		
	@property
	def move_x(self):
		#return self._move_velocity_x.value
		return self.stats['move'].x
	
	@property
	def move_y(self):
		#return self._move_velocity_y.value
		return self.stats['move'].y
		
	@property
	def move_velocity_x(self):
		#return self._move_velocity_x.value
		return self.stats['velocity'].x
	
	@property
	def move_velocity_y(self):
		#return self._move_velocity_y.value
		return self.stats['velocity'].y
	
	@property
	def jumping(self):
		return self.stats['jump']
		
	def jump(self, active = True):
		if active:
			self.stats['jump'] = True

	@property
	def crouching(self):
		return self.stats['jump']
		
	def crouch(self, active = True):
		if active:
			self.stats['crouch'] = not(self.stats['crouch'])
			self['crouch'] = self.stats['crouch']
		
	#def gravity(self,x,y,z):
		
	def update(self, *param):
		if self.testerror:
			self.stop()
		self.testerror = True
		actualTime = time()
		frametime = self['time']
		
		rayResult = self.fallsens.rayCast(self.feet, self, 0, "",1,0,1)
		
		x = self.move_velocity_y
		y = self.move_velocity_x
		z = 0.0
		#self['debug_vitesse'] = '(0.0,0.0,0.0)'
		self['debug_vitesse'] = str(self.stats['velocity'])
		ground = False
		if rayResult[0] != None:
			groundDistance = self.feet.getDistanceTo(rayResult[1])
			groundNormalPlayerSpace = mathutils.Vector(rayResult[2])*self.worldOrientation
			ground = True
			#self['debug_g'] = str((x,y,z))
			if groundNormalPlayerSpace.z < 0.9999:
				angle = groundNormalPlayerSpace.angle((.0,.0,1.0))
				maximum = math.sin(angle)
				angleX = (-(groundNormalPlayerSpace.x/maximum)*angle)*self.move_y
				angleY = (-(groundNormalPlayerSpace.y/maximum)*angle)*self.move_x
				x,y,z = (abs(math.cos(angleX))*x,
						 abs(math.cos(angleY))*y,
					(math.sin(angleX)*abs(x))+(math.sin(angleY)*abs(y)))
				#self['debug_vitesse'] = self['debug_vitesse_avant']+'apres :'+str((x,y,z))+','
				#self['debug_vitesse'] = str((x,y,z))
			if self.jumping:
				z += self.settings['jumpforce']
			#elif 'p' not in self['debug_vitesse']:
			#	self['debug_vitesse_avant'] = 'avant :'+str((x,y,z))+', '
		x,y,z = (((x*self.worldOrientation[0][0])+(y*self.worldOrientation[0][1])+(z*self.worldOrientation[0][2]))*frametime,
				((x*self.worldOrientation[1][0])+(y*self.worldOrientation[1][1])+(z*self.worldOrientation[1][2]))*frametime,
				((x*self.worldOrientation[2][0])+(y*self.worldOrientation[2][1])+(z*self.worldOrientation[2][2]))*frametime)
		if not ground:
			self.stats['jump'] = False
			#self['debug_vitesse'] = 'error'
			self.stats['falling']['fall_time'] += frametime
			z = self.stats['falling']['pre_fall_speed'].z-(self.settings['gravity']*self.stats['falling']['fall_time']*0.22)
		else:
			self.stats['falling']['fall_time'] = .0
			self.stats['falling']['pre_fall_speed'] = mathutils.Vector((x,y,z))
			if not groundDistance < 0.07:
				smooth = z-(groundDistance*self.settings["smoothMoveFactor"])
				if smooth < .0:
					z = z+abs(smooth)
		
		self.characterW.walkDirection = [x,y,z]
		self['time'] = 0.0
		self.testerror = False
		
def InitPlayer(evt,lvl):
	""" Function initializing the player in new level.
	"""
	
	settings = lvl.settings
	stats = lvl.stats
	
	kM = SZ_Globals['keymap']
	keys = (kM['Up'][0],kM['Left'][0],kM['Down'][0],kM['Right'][0])
	
	
	
	"""if 'SZweapon' in lvl.libraries:
		SZ_Globals['LvlScene'].objects["weapon_point"].replaceMesh('357magnum_SZlib1stP')"""
		
	"""if 'SZcharacter' in lvl.libraries:
		gru = SZ_Globals['LvlScene'].objectsInactive["Grugusme"]
		SZ_Globals['LvlScene'].objects["Perso_Principale"].replaceMesh(gru.meshes[0])"""
		
	inpMap = Inputs.InputMap()
	inpMap.layer = 'lvl'
	
	player = Gameplay.ControlledMovement(inpMap,*keys)
	
	pbox = SZ_Globals['LvlScene'].objects["Perso_Pbox"]
	pbox = SZPlayer(pbox,motherOb=player)
	
	weapon = SZHeldWeapon(pbox,
		SZ_Globals['LvlScene'].objects["weapon_point"],
		SZ_Globals['LvlScene'].objects["clip_point"])
	weapon.change_item(Core.load.ItemLoader.loadItem('weapon_test'))
	
	view = SZFirstPersonCam(SZ_Globals['LvlScene'].objects["rotateview"])
	view.x.invert = True
	view.y.invert = True
	view.x.sensitivity = 2.5
	view.activate()
	pbox.activate()
	stats['view'] = view
	stats['player'] = pbox
	stats['weapon'] = weapon
	
Core.load.Level.addStartingCallback(InitPlayer)
	
def startInGame(pre,post):
	lvl = Core.load.Level()
	SZ_Globals['2DScreen'].setLayer("ingame")
	if SZ_Globals['LvlScene'].suspended:
		SZ_Globals['LvlScene'].resume()
		if 'view' in lvl.stats:
			lvl.stats['view'].activate()
def stopInGame(pre,post):
	lvl = Core.load.Level()
	if 'view' in lvl.stats:
			lvl.stats['view'].stop()
	SZ_Globals['LvlScene'].suspend()

SZ_Globals["state_func"]['InGame'] = (startInGame,stopInGame)
